#pragma once
// ========================== reference: LLVM Project =================================

#include <string>

#include "TypeAlias.h"

namespace cal
{
namespace charinfo
{

extern const uint16_t InfoTable[256];
enum {  /* 终端输入字符 */
    CHAR_HORZ_WS  = 0x0001,  // '\t', '\f', '\v'.  Note, no '\0'
    CHAR_VERT_WS  = 0x0002,  // '\r', '\n'
    CHAR_SPACE    = 0x0004,  // ' '
    CHAR_DIGIT    = 0x0008,  // 0-9
    CHAR_UPPER    = 0x0010,  // A-Z
    CHAR_LOWER    = 0x0020,  // a-z
    CHAR_UNDER    = 0x0040,  // _
    CHAR_PERIOD   = 0x0080,  // .
    CHAR_PUNCT    = 0x0100,  // {}[]#<>%:;?*+-/^&|~!=,"'`$@()
};

}   // namespace charinfo

// @brief [_A-Za-z]
inline bool is_identifier_start(unsigned char c)
{
    using namespace charinfo;
    return InfoTable[c] & (CHAR_UNDER | CHAR_UPPER | CHAR_LOWER);
}

// @brief [A-Za-z0-9_]
inline bool is_identifier_continue(unsigned char c)
{
    using namespace charinfo;
    return InfoTable[c] & (CHAR_UPPER | CHAR_LOWER | CHAR_DIGIT | CHAR_UNDER);
}

// @brief [\t\f\v ]
inline bool is_ignorable_white_space(unsigned char c)
{
    using namespace charinfo;
    return InfoTable[c] & (CHAR_HORZ_WS | CHAR_SPACE);
}

inline bool is_printable(unsigned char c) 
{
    using namespace charinfo;
    return (InfoTable[c] & (CHAR_UPPER | CHAR_LOWER | CHAR_PERIOD | CHAR_PUNCT |
                            CHAR_DIGIT | CHAR_UNDER | CHAR_SPACE)) != 0;
}

// such as: '\n' ==> "\\n"、'a' ==> "a"
std::string get_literal_string(unsigned char c);

}   // namespace cal
